/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights
 * reserved. <a>http://www.cqcis.com</a>
 */
package com.cqcis.uip.base.framework.handlers.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPReply;

import com.cqcis.uip.base.framework.UIPServiceException;
import com.cqcis.uip.base.framework.common.Role;
import com.cqcis.uip.base.framework.common.Task;
import com.cqcis.uip.base.framework.core.RegisteredServiceContext;
import com.cqcis.uip.base.framework.core.Service;
import com.cqcis.uip.base.framework.core.ServiceRole;
import com.cqcis.uip.base.framework.core.TaskResultProcessor;
import com.cqcis.uip.base.framework.handlers.CommonService;
import com.cqcis.uip.base.framework.handlers.FtpClientService;
import com.cqcis.uip.base.framework.service.FtpSession;
import com.cqcis.uip.base.framework.service.StreamLogOutputService;
import com.cqcis.uip.base.framework.service.impl.FtpClientSessionImpl;
import com.cqcis.uip.base.framework.utils.LoopThreadPoolExecutor;

/**
 * 默认的FTP客户端封装实现
 * 
 * @author huangmy
 * @date   2008-8-17
 */
public class DefaultFtpClientHandler implements CommonService, Service, TaskResultProcessor {
	private static Log log = LogFactory.getLog(DefaultFtpClientHandler.class);
    private FtpClientService ftpClientService; // 客户端实现
    private int ftpTransferThreadNumber = 1; // FTP传输操作线程数
    private long ftpTransferIntervalTime; // 操作间隔时间
    private LoopThreadPoolExecutor ftpTransferExecutor; // 执行FTP操作线程池    
    private String hostname; // 远程主机IP
    private int port; // 端口
    private String username; // 用户名
    private String password; // 密码
    private Object ftpTransferLock = new Object();
    private Object ftpScheduleLock = new Object();
    private String hostEncoding = "GBK"; // 远程服务器编码
    private StreamLogOutputService streamLogOutputService; // stream log
    
    public boolean processResult(Task task) {
    	if (this.ftpClientService instanceof TaskResultProcessor) {
			return ((TaskResultProcessor)this.ftpClientService).processResult(task);
		}
		return false;
    }
    
	public void start(RegisteredServiceContext serviceContext) throws Exception {
		if (this.ftpClientService instanceof Service) {
			((Service)this.ftpClientService).start(serviceContext);
		}
		
    	this.ftpTransferExecutor = LoopThreadPoolExecutor.getExecutor(this.ftpTransferThreadNumber, this.ftpTransferThreadNumber * 2, 60, 
				serviceContext.getLogService(), serviceContext.getRegisteredService().getLogConfiguration(), 
				"Transfer " + serviceContext.getRegisteredService().getName(), this.ftpTransferIntervalTime);
    	for (int i = 0; i < this.ftpTransferThreadNumber; i ++) {
    		this.ftpTransferExecutor.execute(new Runnable() {
    			public void run() {
    				try {
    					synchronized (ftpTransferLock) {
    						ftpTransferProcess();
						}						
					} catch (Throwable t) {
						log.error("执行FTP操作异常：", t);
					}
    			}
    		});
    	}
	}

	public void stop(RegisteredServiceContext serviceContext) throws Exception {
		if (this.ftpTransferExecutor != null) {
    		this.ftpTransferExecutor.shutdown();
		}
		
		if (this.ftpClientService instanceof Service) {
			((Service)this.ftpClientService).stop(serviceContext);
		}
	}
	
	/**
	 * 执行FTP操作
	 * 
	 * @throws Exception
	 */
	private void ftpTransferProcess() throws Exception {		
		FtpSession session = null;
		try {
			session = createFtpSession(); // 获取ftp客户端session
			if (session == null) {
				throw new UIPServiceException("获取ftp链接为空");
			}
			this.ftpClientService.doTransfer(session);
		} finally {
			if (session != null) {
				session.close();
			}
		}
	}
	
	private FTPClient createFTPMustClient() throws Exception {
		FTPClient ftp = new FTPClient();
	    ftp.configure(this.getFTPClientConfig());		
	    ftp.connect(this.hostname, this.port);		
	    ftp.login(this.username, this.password);
	    ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
	    ftp.enterLocalPassiveMode();// 使用被动模式传输

	    int reply = ftp.getReplyCode();
	    if ((!FTPReply.isPositiveCompletion(reply))
	    		|| (reply != FTPReply.USER_LOGGED_IN && reply != FTPReply.COMMAND_OK)) {
	        ftp.disconnect();
	        throw new UIPServiceException("登录ftp服务器失败,hostname: " + this.hostname
	        		+ ", port: " + this.port + ", username: " + this.username + ", password: " + this.password
	        		+ ", reply = " + reply);
	    }
	    
	    return ftp;
	}
	
	/**
	 * 创建新的ftp客户端连接
	 * 
	 * @return
	 */
	private FtpSession createFtpSession() {	
		try {
		    return new FtpClientSessionImpl(createFTPMustClient(), this.hostEncoding, this.streamLogOutputService) {
		    	@Override
		    	public FTPClient createFTPClient() {
		    		try {
						return createFTPMustClient();
					} catch (Exception e) {
						throw new UIPServiceException(e);
					}
		    	}
		    };
		} catch (Exception ex) {
		    throw new UIPServiceException(ex);
		}
	}
	
	/**
	 * ftp客户端配置
	 * 
	 * @return
	 */
	private FTPClientConfig getFTPClientConfig() {
		FTPClientConfig conf = new FTPClientConfig();
		return conf; 
	}
	
	public void schedule(Task task) throws Exception {
		synchronized (this.ftpScheduleLock) {
			FtpSession session = null;
			try {
				session = createFtpSession(); // 获取ftp客户端session
				if (session == null) {
					throw new UIPServiceException("获取ftp链接为空");
				}
				this.ftpClientService.schedule(task, session);
			} finally {
				if (session != null) {
					session.close();
				}
			}			
		}		
	}
    
	@ServiceRole(Role.FTP_CLIENT)
	public void setFtpClientService(FtpClientService ftpClientService) {
		this.ftpClientService = ftpClientService;
	}

	public void setFtpTransferIntervalTime(long ftpTransferIntervalTime) {
		this.ftpTransferIntervalTime = ftpTransferIntervalTime;
	}

	public void setHostname(String hostname) {
		this.hostname = hostname;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public void setHostEncoding(String hostEncoding) {
		this.hostEncoding = hostEncoding;
	}

	public void setStreamLogOutputService(
			StreamLogOutputService streamLogOutputService) {
		this.streamLogOutputService = streamLogOutputService;
	}
}
